// IFC String decoding
// https://technical.buildingsmart.org/resources/ifcimplementationguidance/string-encoding/
// http://www.steptools.com/stds/step/IS_final_p21e3.html


#include <vector>
#include <string>
#include <sstream>
#include <iomanip>
#include <codecvt>
#include <locale>
#include <cstdint>

namespace webifc::parsing {

    bool foundRoman = false;

    void encodeCharacters(std::ostringstream &stream,std::string &data) 
    {
        std::u16string utf16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(data.data());
        stream << "\\X2\\" << std::hex <<std::setfill('0') << std::uppercase;
        for (char16_t uC : utf16) stream << std::setw(4) << static_cast<int>(uC);
        stream << std::dec<< std::setw(0) << "\\X0\\";
    }

    void p21encode(std::string_view input, std::ostringstream &output)
    {   
        std::string tmp;
        bool inEncode=false;
        for (char c : input) {
          if (c > 126 || c < 32) { 
            if (!inEncode) 
            {
              inEncode = true;
              tmp=c;
              continue;
            } else {
              tmp+=c;
              continue;
            }
          } else {
            if (inEncode) {
                encodeCharacters(output,tmp);
                inEncode=false;
                tmp.clear();
            } else if (c==39) {
                output << c << c;
                continue;
            }
          }
          output << c;
        }
        if (inEncode) encodeCharacters(output,tmp);
    }

    struct P21Decoder
    {
        public:
            P21Decoder(std::string_view &str)
            {
                error=false;
                iter=str.begin();
                codepage=0;
                end=str.end();
                if (str.size() == 0) {
                    // msvc: avoid dereference `iter.end()` when _ITERATOR_DEBUG_LEVEL >= 1
                    return;
                }
                for (char c=*iter; c != 0 && !error; c=getNext())
                {
                    switch (c) 
                    {
                        case '\'':
                        {
                            char c = getNext();
                            if (c==0) return;
                            if (c == '\'') result.push_back(c);
                            else error=true;
                            break;
                        }
                        case '\\':
                        {
                            char c = getNext();
                            if (c==0) return;
                            switch (c) {
                                case '\\':
                                    result.push_back('\\');
                                    break;
                                case 'X':
                                {
                                    char c = getNext();
                                    if (c==0) return;
                                    switch (c) {
                                        case '\\':
                                         {
                                            char d1 = getNextHex();
                                            char d2 = getNextHex();
                                            char str[2];
                                            str[0] = (d1 << 4) | d2;
                                            str[1] = 0;
                                            auto cA = reinterpret_cast<char16_t*>(str);
                                            if (cA[0] >= 0x80 && cA[0] <= 0x9F) foundRoman = true;
                                            if (foundRoman) cA[0]=checkRomanEncoding(cA[0]);
                                            std::u16string u16str(cA, 1);
                                            std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert; 
                                            std::string utf8 = convert.to_bytes(u16str);
                                            std::copy(utf8.begin(), utf8.end(), std::back_inserter(result));
                                            break;
                                        }
                                        case '2':
                                        {
                                            parse_x<2>();
                                            break;
                                        }
                                        case '4':
                                        { 
                                            parse_x<4>();
                                            break;
                                        }
                                         default:
                                            error=true;
                                            break;
                                    }
                                    break;
                                }
                                case 'S':
                                {
                                    if (getNext() != '\\') 
                                    {
                                        error=true;
                                        return;
                                    }
                                    const char * bytes = iso8859_to_utf(getNext());
                                    for (int i = 0; i < 3; i++)
                                    {
                                        if (bytes[i] == 0) break;
                                        result.push_back(bytes[i]);
                                    }
                                    break;
                                }
                                case 'P':
                                {
                                    char c1 = getNext();
                                    if (c1==0) return;
                                    if (getNext() != '\\')
                                     {
                                        error=true;
                                        return;
                                    }
                                    if (c1 < 'A' || c1 > 'I') {
                                        error=true;
                                        return;
                                    }
                                    codepage = c1 - 'A';
                                    break;
                                }
                                default:
                                    error=true;
                                    break;
                            }
                            break;
                        }
                        default:
                            result.push_back(c);
                            break;
                    }
                }
            } 

            std::vector<char> &GetResult()
            {
                return result;
            }
            bool GetError() 
            {
                return error;
            }
        private:
            std::string_view::iterator iter;
            std::string_view::iterator end;
            unsigned char codepage;
            std::vector<char> result;
            bool error;
            constexpr static const char table[9][95][3] = {{{-62,-95,0},{-62,-94,0},{-62,-93,0},{-62,-92,0},{-62,-91,0},{-62,-90,0},{-62,-89,0},{-62,-88,0},{-62,-87,0},{-62,-86,0},{-62,-85,0},{-62,-84,0},{-62,-83,0},{-62,-82,0},{-62,-81,0},{-62,-80,0},{-62,-79,0},{-62,-78,0},{-62,-77,0},{-62,-76,0},{-62,-75,0},{-62,-74,0},{-62,-73,0},{-62,-72,0},{-62,-71,0},{-62,-70,0},{-62,-69,0},{-62,-68,0},{-62,-67,0},{-62,-66,0},{-62,-65,0},{-61,-128,0},{-61,-127,0},{-61,-126,0},{-61,-125,0},{-61,-124,0},{-61,-123,0},{-61,-122,0},{-61,-121,0},{-61,-120,0},{-61,-119,0},{-61,-118,0},{-61,-117,0},{-61,-116,0},{-61,-115,0},{-61,-114,0},{-61,-113,0},{-61,-112,0},{-61,-111,0},{-61,-110,0},{-61,-109,0},{-61,-108,0},{-61,-107,0},{-61,-106,0},{-61,-105,0},{-61,-104,0},{-61,-103,0},{-61,-102,0},{-61,-101,0},{-61,-100,0},{-61,-99,0},{-61,-98,0},{-61,-97,0},{-61,-96,0},{-61,-95,0},{-61,-94,0},{-61,-93,0},{-61,-92,0},{-61,-91,0},{-61,-90,0},{-61,-89,0},{-61,-88,0},{-61,-87,0},{-61,-86,0},{-61,-85,0},{-61,-84,0},{-61,-83,0},{-61,-82,0},{-61,-81,0},{-61,-80,0},{-61,-79,0},{-61,-78,0},{-61,-77,0},{-61,-76,0},{-61,-75,0},{-61,-74,0},{-61,-73,0},{-61,-72,0},{-61,-71,0},{-61,-70,0},{-61,-69,0},{-61,-68,0},{-61,-67,0},{-61,-66,0},{-61,-65,0}},{{-60,-124,0},{-53,-104,0},{-59,-127,0},{-62,-92,0},{-60,-67,0},{-59,-102,0},{-62,-89,0},{-62,-88,0},{-59,-96,0},{-59,-98,0},{-59,-92,0},{-59,-71,0},{-62,-83,0},{-59,-67,0},{-59,-69,0},{-62,-80,0},{-60,-123,0},{-53,-101,0},{-59,-126,0},{-62,-76,0},{-60,-66,0},{-59,-101,0},{-53,-121,0},{-62,-72,0},{-59,-95,0},{-59,-97,0},{-59,-91,0},{-59,-70,0},{-53,-99,0},{-59,-66,0},{-59,-68,0},{-59,-108,0},{-61,-127,0},{-61,-126,0},{-60,-126,0},{-61,-124,0},{-60,-71,0},{-60,-122,0},{-61,-121,0},{-60,-116,0},{-61,-119,0},{-60,-104,0},{-61,-117,0},{-60,-102,0},{-61,-115,0},{-61,-114,0},{-60,-114,0},{-60,-112,0},{-59,-125,0},{-59,-121,0},{-61,-109,0},{-61,-108,0},{-59,-112,0},{-61,-106,0},{-61,-105,0},{-59,-104,0},{-59,-82,0},{-61,-102,0},{-59,-80,0},{-61,-100,0},{-61,-99,0},{-59,-94,0},{-61,-97,0},{-59,-107,0},{-61,-95,0},{-61,-94,0},{-60,-125,0},{-61,-92,0},{-60,-70,0},{-60,-121,0},{-61,-89,0},{-60,-115,0},{-61,-87,0},{-60,-103,0},{-61,-85,0},{-60,-101,0},{-61,-83,0},{-61,-82,0},{-60,-113,0},{-60,-111,0},{-59,-124,0},{-59,-120,0},{-61,-77,0},{-61,-76,0},{-59,-111,0},{-61,-74,0},{-61,-73,0},{-59,-103,0},{-59,-81,0},{-61,-70,0},{-59,-79,0},{-61,-68,0},{-61,-67,0},{-59,-93,0},{-53,-103,0}},{{-60,-90,0},{-53,-104,0},{-62,-93,0},{-62,-92,0},{-17,-97,-75},{-60,-92,0},{-62,-89,0},{-62,-88,0},{-60,-80,0},{-59,-98,0},{-60,-98,0},{-60,-76,0},{-62,-83,0},{-17,-97,-74},{-59,-69,0},{-62,-80,0},{-60,-89,0},{-62,-78,0},{-62,-77,0},{-62,-76,0},{-62,-75,0},{-60,-91,0},{-62,-73,0},{-62,-72,0},{-60,-79,0},{-59,-97,0},{-60,-97,0},{-60,-75,0},{-62,-67,0},{-17,-97,-73},{-59,-68,0},{-61,-128,0},{-61,-127,0},{-61,-126,0},{-17,-97,-72},{-61,-124,0},{-60,-118,0},{-60,-120,0},{-61,-121,0},{-61,-120,0},{-61,-119,0},{-61,-118,0},{-61,-117,0},{-61,-116,0},{-61,-115,0},{-61,-114,0},{-61,-113,0},{-17,-97,-71},{-61,-111,0},{-61,-110,0},{-61,-109,0},{-61,-108,0},{-60,-96,0},{-61,-106,0},{-61,-105,0},{-60,-100,0},{-61,-103,0},{-61,-102,0},{-61,-101,0},{-61,-100,0},{-59,-84,0},{-59,-100,0},{-61,-97,0},{-61,-96,0},{-61,-95,0},{-61,-94,0},{-17,-97,-70},{-61,-92,0},{-60,-117,0},{-60,-119,0},{-61,-89,0},{-61,-88,0},{-61,-87,0},{-61,-86,0},{-61,-85,0},{-61,-84,0},{-61,-83,0},{-61,-82,0},{-61,-81,0},{-17,-97,-69},{-61,-79,0},{-61,-78,0},{-61,-77,0},{-61,-76,0},{-60,-95,0},{-61,-74,0},{-61,-73,0},{-60,-99,0},{-61,-71,0},{-61,-70,0},{-61,-69,0},{-61,-68,0},{-59,-83,0},{-59,-99,0},{-53,-103,0}},{{-60,-124,0},{-60,-72,0},{-59,-106,0},{-62,-92,0},{-60,-88,0},{-60,-69,0},{-62,-89,0},{-62,-88,0},{-59,-96,0},{-60,-110,0},{-60,-94,0},{-59,-90,0},{-62,-83,0},{-59,-67,0},{-62,-81,0},{-62,-80,0},{-60,-123,0},{-53,-101,0},{-59,-105,0},{-62,-76,0},{-60,-87,0},{-60,-68,0},{-53,-121,0},{-62,-72,0},{-59,-95,0},{-60,-109,0},{-60,-93,0},{-59,-89,0},{-59,-118,0},{-59,-66,0},{-59,-117,0},{-60,-128,0},{-61,-127,0},{-61,-126,0},{-61,-125,0},{-61,-124,0},{-61,-123,0},{-61,-122,0},{-60,-82,0},{-60,-116,0},{-61,-119,0},{-60,-104,0},{-61,-117,0},{-60,-106,0},{-61,-115,0},{-61,-114,0},{-60,-86,0},{-60,-112,0},{-59,-123,0},{-59,-116,0},{-60,-74,0},{-61,-108,0},{-61,-107,0},{-61,-106,0},{-61,-105,0},{-61,-104,0},{-59,-78,0},{-61,-102,0},{-61,-101,0},{-61,-100,0},{-59,-88,0},{-59,-86,0},{-61,-97,0},{-60,-127,0},{-61,-95,0},{-61,-94,0},{-61,-93,0},{-61,-92,0},{-61,-91,0},{-61,-90,0},{-60,-81,0},{-60,-115,0},{-61,-87,0},{-60,-103,0},{-61,-85,0},{-60,-105,0},{-61,-83,0},{-61,-82,0},{-60,-85,0},{-60,-111,0},{-59,-122,0},{-59,-115,0},{-60,-73,0},{-61,-76,0},{-61,-75,0},{-61,-74,0},{-61,-73,0},{-61,-72,0},{-59,-77,0},{-61,-70,0},{-61,-69,0},{-61,-68,0},{-59,-87,0},{-59,-85,0},{-53,-103,0}},{{-48,-127,0},{-48,-126,0},{-48,-125,0},{-48,-124,0},{-48,-123,0},{-48,-122,0},{-48,-121,0},{-48,-120,0},{-48,-119,0},{-48,-118,0},{-48,-117,0},{-48,-116,0},{-62,-83,0},{-48,-114,0},{-48,-113,0},{-48,-112,0},{-48,-111,0},{-48,-110,0},{-48,-109,0},{-48,-108,0},{-48,-107,0},{-48,-106,0},{-48,-105,0},{-48,-104,0},{-48,-103,0},{-48,-102,0},{-48,-101,0},{-48,-100,0},{-48,-99,0},{-48,-98,0},{-48,-97,0},{-48,-96,0},{-48,-95,0},{-48,-94,0},{-48,-93,0},{-48,-92,0},{-48,-91,0},{-48,-90,0},{-48,-89,0},{-48,-88,0},{-48,-87,0},{-48,-86,0},{-48,-85,0},{-48,-84,0},{-48,-83,0},{-48,-82,0},{-48,-81,0},{-48,-80,0},{-48,-79,0},{-48,-78,0},{-48,-77,0},{-48,-76,0},{-48,-75,0},{-48,-74,0},{-48,-73,0},{-48,-72,0},{-48,-71,0},{-48,-70,0},{-48,-69,0},{-48,-68,0},{-48,-67,0},{-48,-66,0},{-48,-65,0},{-47,-128,0},{-47,-127,0},{-47,-126,0},{-47,-125,0},{-47,-124,0},{-47,-123,0},{-47,-122,0},{-47,-121,0},{-47,-120,0},{-47,-119,0},{-47,-118,0},{-47,-117,0},{-47,-116,0},{-47,-115,0},{-47,-114,0},{-47,-113,0},{-30,-124,-106},{-47,-111,0},{-47,-110,0},{-47,-109,0},{-47,-108,0},{-47,-107,0},{-47,-106,0},{-47,-105,0},{-47,-104,0},{-47,-103,0},{-47,-102,0},{-47,-101,0},{-47,-100,0},{-62,-89,0},{-47,-98,0},{-47,-97,0}},{{-17,-97,-120},{-17,-97,-119},{-17,-97,-118},{-62,-92,0},{-17,-97,-117},{-17,-97,-116},{-17,-97,-115},{-17,-97,-114},{-17,-97,-113},{-17,-97,-112},{-17,-97,-111},{-40,-116,0},{-62,-83,0},{-17,-97,-110},{-17,-97,-109},{-17,-97,-108},{-17,-97,-107},{-17,-97,-106},{-17,-97,-105},{-17,-97,-104},{-17,-97,-103},{-17,-97,-102},{-17,-97,-101},{-17,-97,-100},{-17,-97,-99},{-17,-97,-98},{-40,-101,0},{-17,-97,-97},{-17,-97,-96},{-17,-97,-95},{-40,-97,0},{-17,-97,-94},{-40,-95,0},{-40,-94,0},{-40,-93,0},{-40,-92,0},{-40,-91,0},{-40,-90,0},{-40,-89,0},{-40,-88,0},{-40,-87,0},{-40,-86,0},{-40,-85,0},{-40,-84,0},{-40,-83,0},{-40,-82,0},{-40,-81,0},{-40,-80,0},{-40,-79,0},{-40,-78,0},{-40,-77,0},{-40,-76,0},{-40,-75,0},{-40,-74,0},{-40,-73,0},{-40,-72,0},{-40,-71,0},{-40,-70,0},{-17,-97,-93},{-17,-97,-92},{-17,-97,-91},{-17,-97,-90},{-17,-97,-89},{-39,-128,0},{-39,-127,0},{-39,-126,0},{-39,-125,0},{-39,-124,0},{-39,-123,0},{-39,-122,0},{-39,-121,0},{-39,-120,0},{-39,-119,0},{-39,-118,0},{-39,-117,0},{-39,-116,0},{-39,-115,0},{-39,-114,0},{-39,-113,0},{-39,-112,0},{-39,-111,0},{-39,-110,0},{-17,-97,-88},{-17,-97,-87},{-17,-97,-86},{-17,-97,-85},{-17,-97,-84},{-17,-97,-83},{-17,-97,-82},{-17,-97,-81},{-17,-97,-80},{-17,-97,-79},{-17,-97,-78},{-17,-97,-77},{-17,-97,-76}},{{-54,-67,0},{-54,-68,0},{-62,-93,0},{-17,-97,-126},{-17,-97,-125},{-62,-90,0},{-62,-89,0},{-62,-88,0},{-62,-87,0},{-17,-97,-124},{-62,-85,0},{-62,-84,0},{-62,-83,0},{-17,-97,-123},{-30,-128,-107},{-62,-80,0},{-62,-79,0},{-62,-78,0},{-62,-77,0},{-50,-124,0},{-50,-123,0},{-50,-122,0},{-62,-73,0},{-50,-120,0},{-50,-119,0},{-50,-118,0},{-62,-69,0},{-50,-116,0},{-62,-67,0},{-50,-114,0},{-50,-113,0},{-50,-112,0},{-50,-111,0},{-50,-110,0},{-50,-109,0},{-50,-108,0},{-50,-107,0},{-50,-106,0},{-50,-105,0},{-50,-104,0},{-50,-103,0},{-50,-102,0},{-50,-101,0},{-50,-100,0},{-50,-99,0},{-50,-98,0},{-50,-97,0},{-50,-96,0},{-50,-95,0},{-17,-97,-122},{-50,-93,0},{-50,-92,0},{-50,-91,0},{-50,-90,0},{-50,-89,0},{-50,-88,0},{-50,-87,0},{-50,-86,0},{-50,-85,0},{-50,-84,0},{-50,-83,0},{-50,-82,0},{-50,-81,0},{-50,-80,0},{-50,-79,0},{-50,-78,0},{-50,-77,0},{-50,-76,0},{-50,-75,0},{-50,-74,0},{-50,-73,0},{-50,-72,0},{-50,-71,0},{-50,-70,0},{-50,-69,0},{-50,-68,0},{-50,-67,0},{-50,-66,0},{-50,-65,0},{-49,-128,0},{-49,-127,0},{-49,-126,0},{-49,-125,0},{-49,-124,0},{-49,-123,0},{-49,-122,0},{-49,-121,0},{-49,-120,0},{-49,-119,0},{-49,-118,0},{-49,-117,0},{-49,-116,0},{-49,-115,0},{-49,-114,0},{-17,-97,-121}},{{-17,-98,-100},{-62,-94,0},{-62,-93,0},{-62,-92,0},{-62,-91,0},{-62,-90,0},{-62,-89,0},{-62,-88,0},{-62,-87,0},{-61,-105,0},{-62,-85,0},{-62,-84,0},{-62,-83,0},{-62,-82,0},{-30,-128,-66},{-62,-80,0},{-62,-79,0},{-62,-78,0},{-62,-77,0},{-62,-76,0},{-62,-75,0},{-62,-74,0},{-62,-73,0},{-62,-72,0},{-62,-71,0},{-61,-73,0},{-62,-69,0},{-62,-68,0},{-62,-67,0},{-62,-66,0},{-17,-98,-99},{-17,-98,-98},{-17,-98,-97},{-17,-98,-96},{-17,-98,-95},{-17,-98,-94},{-17,-98,-93},{-17,-98,-92},{-17,-98,-91},{-17,-98,-90},{-17,-98,-89},{-17,-98,-88},{-17,-98,-87},{-17,-98,-86},{-17,-98,-85},{-17,-98,-84},{-17,-98,-83},{-17,-98,-82},{-17,-98,-81},{-17,-98,-80},{-17,-98,-79},{-17,-98,-78},{-17,-98,-77},{-17,-98,-76},{-17,-98,-75},{-17,-98,-74},{-17,-98,-73},{-17,-98,-72},{-17,-98,-71},{-17,-98,-70},{-17,-98,-69},{-17,-98,-68},{-30,-128,-105},{-41,-112,0},{-41,-111,0},{-41,-110,0},{-41,-109,0},{-41,-108,0},{-41,-107,0},{-41,-106,0},{-41,-105,0},{-41,-104,0},{-41,-103,0},{-41,-102,0},{-41,-101,0},{-41,-100,0},{-41,-99,0},{-41,-98,0},{-41,-97,0},{-41,-96,0},{-41,-95,0},{-41,-94,0},{-41,-93,0},{-41,-92,0},{-41,-91,0},{-41,-90,0},{-41,-89,0},{-41,-88,0},{-41,-87,0},{-41,-86,0},{-17,-98,-67},{-17,-98,-66},{-17,-98,-65},{-17,-97,-128},{-17,-97,-127}},{{-62,-95,0},{-62,-94,0},{-62,-93,0},{-62,-92,0},{-62,-91,0},{-62,-90,0},{-62,-89,0},{-62,-88,0},{-62,-87,0},{-62,-86,0},{-62,-85,0},{-62,-84,0},{-62,-83,0},{-62,-82,0},{-62,-81,0},{-62,-80,0},{-62,-79,0},{-62,-78,0},{-62,-77,0},{-62,-76,0},{-62,-75,0},{-62,-74,0},{-62,-73,0},{-62,-72,0},{-62,-71,0},{-62,-70,0},{-62,-69,0},{-62,-68,0},{-62,-67,0},{-62,-66,0},{-62,-65,0},{-61,-128,0},{-61,-127,0},{-61,-126,0},{-61,-125,0},{-61,-124,0},{-61,-123,0},{-61,-122,0},{-61,-121,0},{-61,-120,0},{-61,-119,0},{-61,-118,0},{-61,-117,0},{-61,-116,0},{-61,-115,0},{-61,-114,0},{-61,-113,0},{-60,-98,0},{-61,-111,0},{-61,-110,0},{-61,-109,0},{-61,-108,0},{-61,-107,0},{-61,-106,0},{-61,-105,0},{-61,-104,0},{-61,-103,0},{-61,-102,0},{-61,-101,0},{-61,-100,0},{-60,-80,0},{-59,-98,0},{-61,-97,0},{-61,-96,0},{-61,-95,0},{-61,-94,0},{-61,-93,0},{-61,-92,0},{-61,-91,0},{-61,-90,0},{-61,-89,0},{-61,-88,0},{-61,-87,0},{-61,-86,0},{-61,-85,0},{-61,-84,0},{-61,-83,0},{-61,-82,0},{-61,-81,0},{-60,-97,0},{-61,-79,0},{-61,-78,0},{-61,-77,0},{-61,-76,0},{-61,-75,0},{-61,-74,0},{-61,-73,0},{-61,-72,0},{-61,-71,0},{-61,-70,0},{-61,-69,0},{-61,-68,0},{-60,-79,0},{-59,-97,0},{-61,-65,0}}};
            const char* iso8859_to_utf(const unsigned char symbol) const
            {
                // Converting tables ISO 8859-x -> UTF-8
                // Each table has utf-8 bytes for symbols 0xa1 .. 0xff
                return table[codepage][symbol - 0x21];
            }
            char getNextHex() 
            {
                char value = getNext();
                if (value >= '0' && value <= '9') return value - '0';
                if (value >= 'A' && value <= 'F') return value - 'A' + 10;
                return 0;
            }
            char getNext()
            {
                iter = std::next(iter);
                if (iter!=end) return *iter;
                return (char)0;
            }
            template<int T>
            void parse_x() {
                if (getNext() != '\\')
                {
                    error=true;
                    return;
                };
                std::vector<char> bytes;
                while (1)
                {
                    char c = getNext();
                    if ( c == 0)
                    {
                        error=true;
                        return;
                    };
                    if (c == '\\') {
                        if (getNext() == 'X' && getNext() =='0' && getNext() == '\\') break;
                        error=true;
                        return;
                    }  else {
                        iter=std::prev(iter);
                        char d1 = getNextHex();
                        char d2 = getNextHex();
                        bytes.push_back((d1 << 4) | d2);
                    }
                }
                std::string utf8;

                if (T == 2) {
                    for (uint32_t i = 0; i < bytes.size(); i+=2) {
                        char c = bytes[i];
                        bytes[i] = bytes[i+1];
                        bytes[i+1] = c;
                    }
                    std::u16string u16str(reinterpret_cast<char16_t*>(&bytes[0]), bytes.size() / 2);
                    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert; 
                    utf8 = convert.to_bytes(u16str);
                } 
                else if (T == 4) 
                {
                    for (uint32_t i = 0; i < bytes.size(); i+=4) {
                        char c = bytes[i];
                        bytes[i] = bytes[i+3];
                        bytes[i+3] = c;
                        c = bytes[i+1];
                        bytes[i+1] = bytes[i+2];
                        bytes[i+2] = c;
                    }
                    std::u32string u32str(reinterpret_cast<char32_t*>(&bytes[0]), bytes.size() / 4);
                    std::wstring_convert<std::codecvt_utf8<char32_t>,char32_t> convert; 
                    utf8 = convert.to_bytes(u32str);
                }
                std::copy(utf8.begin(), utf8.end(), std::back_inserter(result));
            }

            const char16_t checkRomanEncoding(char16_t input) const
            {
                if (input < 0x80 || input > 0xFF) return input;
                switch (input)
                {
                    case 0x80: return 196;
                    case 0x81: return 197;
                    case 0x82: return 199;
                    case 0x83: return 201;
                    case 0x84: return 209;
                    case 0x85: return 214;
                    case 0x86: return 220;
                    case 0x87: return 225;
                    case 0x88: return 224;
                    case 0x89: return 226;
                    case 0x8A: return 228;
                    case 0x8B: return 227;
                    case 0x8C: return 229;
                    case 0x8D: return 231;
                    case 0x8E: return 233;
                    case 0x8F: return 232;
                    case 0x90: return 234;
                    case 0x91: return 235;
                    case 0x92: return 237;
                    case 0x93: return 236;
                    case 0x94: return 238;
                    case 0x95: return 239;
                    case 0x96: return 241;
                    case 0x97: return 243;
                    case 0x98: return 242;
                    case 0x99: return 244;
                    case 0x9A: return 246;
                    case 0x9B: return 245;
                    case 0x9C: return 250;
                    case 0x9D: return 249;
                    case 0x9E: return 251;
                    case 0x9F: return 252;
                    case 0xA0: return 8224;
                    case 0xA1: return 176;
                    case 0xA2: return 162;
                    case 0xA3: return 163;
                    case 0xA4: return 167;
                    case 0xA5: return 8226;
                    case 0xA6: return 182;
                    case 0xA7: return 223;
                    case 0xA8: return 174;
                    case 0xA9: return 169;
                    case 0xAA: return 8482;
                    case 0xAB: return 180;
                    case 0xAC: return 168;
                    case 0xAD: return 8800;
                    case 0xAE: return 198;
                    case 0xAF: return 216;
                    case 0xB0: return 8734;
                    case 0xB1: return 177;
                    case 0xB2: return 8804;
                    case 0xB3: return 8805;
                    case 0xB4: return 165;
                    case 0xB5: return 181;
                    case 0xB6: return 8706;
                    case 0xB7: return 8721;
                    case 0xB8: return 8719;
                    case 0xB9: return 960;
                    case 0xBA: return 8747;
                    case 0xBB: return 170;
                    case 0xBC: return 186;
                    case 0xBD: return 937;
                    case 0xBE: return 230;
                    case 0xBF: return 248;
                    case 0xC0: return 191;
                    case 0xC1: return 161;
                    case 0xC2: return 172;
                    case 0xC3: return 8730;
                    case 0xC4: return 402;
                    case 0xC5: return 8776;
                    case 0xC6: return 8710;
                    case 0xC7: return 171;
                    case 0xC8: return 187;
                    case 0xC9: return 8230;
                    case 0xCA: return 160;
                    case 0xCB: return 192;
                    case 0xCC: return 195;
                    case 0xCD: return 213;
                    case 0xCE: return 338;
                    case 0xCF: return 339;
                    case 0xD0: return 8211;
                    case 0xD1: return 8212;
                    case 0xD2: return 8220;
                    case 0xD3: return 8221;
                    case 0xD4: return 8216;
                    case 0xD5: return 8217;
                    case 0xD6: return 247;
                    case 0xD7: return 9674;
                    case 0xD8: return 255;
                    case 0xD9: return 376;
                    case 0xDA: return 8260;
                    case 0xDB: return 8364;
                    case 0xDC: return 8249;
                    case 0xDD: return 8250;
                    case 0xDE: return 64257;
                    case 0xDF: return 64258;
                    case 0xE0: return 8225;
                    case 0xE1: return 183;
                    case 0xE2: return 8218;
                    case 0xE3: return 8222;
                    case 0xE4: return 8240;
                    case 0xE5: return 194;
                    case 0xE6: return 202;
                    case 0xE7: return 193;
                    case 0xE8: return 203;
                    case 0xE9: return 200;
                    case 0xEA: return 205;
                    case 0xEB: return 206;
                    case 0xEC: return 207;
                    case 0xED: return 204;
                    case 0xEE: return 211;
                    case 0xEF: return 212;
                    case 0xF0: return 63743;
                    case 0xF1: return 210;
                    case 0xF2: return 218;
                    case 0xF3: return 219;
                    case 0xF4: return 217;
                    case 0xF5: return 305;
                    case 0xF6: return 710;
                    case 0xF7: return 732;
                    case 0xF8: return 175;
                    case 0xF9: return 728;
                    case 0xFA: return 729;
                    case 0xFB: return 730;
                    case 0xFC: return 184;
                    case 0xFD: return 733;
                    case 0xFE: return 731;
                    case 0xFF: return 711;
                }
                return input;
            }
        
    };

       
    std::string p21decode(std::string_view & str) {
        P21Decoder decoder(str);
        if (decoder.GetError()) return {};
        std::vector<char> results = decoder.GetResult();
        return std::string(results.begin(),results.end());
    }

}